package com.su.lightthings.bluetooth

import android.annotation.SuppressLint
import android.util.Log
import com.su.lightthings.bean.HomeFutureWeatherBean
import com.su.lightthings.bean.HomeWeatherBean
import com.su.lightthings.bean.HomeZoneBean
import com.su.lightthings.utils.ByteUtils
import com.su.lightthings.utils.padTo
import com.su.lightthings.utils.toByteArray
import com.su.lightthings.viewmodel.CommonViewModel
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.TimeZone
import kotlin.experimental.or
import kotlin.math.absoluteValue
import kotlin.math.pow

/**
 * 组合协议工具类
 * 仅关注数据部分，不关注功能码和数据长度
 */
object ProtocolDataUtil {
    private const val TAG = "ProtocolDataUtil"

    //region 基础信息

    /**
     * 设备版本号0X0003
     */
    fun getVersion(): ByteArray = byteArrayOf()


    //region 绑定类
    /**
     * 绑定0X0101
     */
    fun bind(): ByteArray = byteArrayOf()

    /**
     * 支持的功能列表
     */
    fun geFunctionList(): ByteArray = byteArrayOf()

    //endregion


    //region 设置类

    /**
     * 计步目标0X0201
     * @param step 步数
     */
    fun stepTarget(step: Int): ByteArray {
        return step.toByteArray()
    }

    /**
     *  亮屏时间设置0X0202
     *  @param second 亮屏时间 00：常亮， 01~3C：亮屏1~60秒
     */
    fun screenBright(second: Int): ByteArray {
        return byteArrayOf(second.toByte())
    }

    /**
     * 时间范围型功能通用方法
     * @param switch 开关状态（0：关闭，1：打开）
     */
    fun commonTimeRange(
        switch: Int,
        startHour: Int,
        startMinute: Int,
        endHout: Int,
        endMinute: Int,
        duration: Int
    ): ByteArray {
        return byteArrayOf(
            switch.toByte(),
            startHour.toByte(),
            startMinute.toByte(),
            endHout.toByte(),
            endMinute.toByte(),
            duration.toByte()
        )
    }

    /**
     * 时间范围型功能通用方法
     * @param switch 开关状态（0：关闭，1：打开）
     */
    fun commonRadioGroup(result: Int): ByteArray {
        return byteArrayOf(
            result.toByte()
        )
    }

    /**
     * 久坐设置0X0203
     * @param switch 开关状态（0：关闭，1：打开）
     */
    fun longSit(
        switch: Int,
        startHour: Int,
        startMinute: Int,
        endHout: Int,
        endMinute: Int,
        duration: Int
    ): ByteArray {
        return byteArrayOf(
            switch.toByte(),
            startHour.toByte(),
            startMinute.toByte(),
            endHout.toByte(),
            endMinute.toByte(),
            duration.toByte()
        )
    }

    /**
     * 勿扰设置0X0204：
     * @param switch 开关状态（0：关闭，1：打开，2：全天打开）
     */
    fun doNotDisturb(
        switch: Int,
        startHour: Int,
        startMinute: Int,
        endHout: Int,
        endMinute: Int
    ): ByteArray {
        return byteArrayOf(
            switch.toByte(),
            startHour.toByte(),
            startMinute.toByte(),
            endHout.toByte(),
            endMinute.toByte()
        )
    }

    /**
     * 震动设置0X0205
     * @param level "震动强度：01：弱  02：中  03强"
     * @param times 震动次数：0~10次
     */
    fun shake(level: Int, times: Int): ByteArray {
        return byteArrayOf(level.toByte(), times.toByte())
    }

    /**
     * 抬手亮屏设置0X0206
     * @param switch 开关状态（0：关闭，1：打开）
     */
    fun handBrighten(
        switch: Int,
        startHour: Int,
        startMinute: Int,
        endHout: Int,
        endMinute: Int
    ): ByteArray {
        return byteArrayOf(
            switch.toByte(),
            startHour.toByte(),
            startMinute.toByte(),
            endHout.toByte(),
            endMinute.toByte()
        )
    }

    /**
     *  12/24小时制设置0X0207
     *  @param type 0：24小时制，1：12小时制
     */
    fun hourType(type: Int): ByteArray = byteArrayOf(type.toByte())

    /**
     *  语言设置0X0207
     *  @param language 语言种类
     *   0x00	简体中文
     *   0x01	繁体中文
     *   0x02	英语
     *   0x03	西班牙语
     *   0x04	俄语
     *   0x05	日语
     *   0x06	韩语
     *   0x07	法语
     *   0x08	葡萄牙语
     */
    fun language(language: Int): ByteArray = byteArrayOf(language.toByte())

    /**
     * 闹钟设置0X0209
     * @param type 闹钟类型："新增：0X00 修改：0X01 删除：0X02"
     * @param id 闹钟ID（0~255）
     * @param switch 开关状态（0：关闭，1：打开）
     * @param repeat 是否重复
     * @param dayOfWeek "bit0：（0：单次，1：重复） bit1~7：对应周一到周日"
     */
    fun alarm(
        type: Int,
        id: Int,
        switch: Int,
        repeat: Boolean,
        hour: Int,
        minute: Int,
        dayOfWeek: MutableList<Int>
    ): ByteArray {
        val result = ByteArray(6)
        var data3 = 0x00.toByte()
        Log.d(TAG, "week: $dayOfWeek")
        for ((i, day) in dayOfWeek.withIndex()) {
            if (day != 0)
                data3 = (data3 + 2.0.pow(i.toDouble()).toInt().toByte()).toByte()
        }
//        data3 = data3 or if (repeat) 0x01.toByte() else 0x00
        data3 = data3.times(2).toByte()
        Log.d(TAG, "repeat: $repeat")
        if (repeat) data3++
        Log.d(TAG, "data3: $data3")

        result[0] = type.toByte()
        result[1] = id.toByte()
        result[2] = switch.toByte()
        result[3] = data3
        result[4] = hour.toByte()
        result[5] = minute.toByte()

        return result
    }

    /**
     * 消息通知开关设置0X020A
     * @param switch 总开关（0：关闭，1：打开）
     * @param appList 消息列表
     * todo
     */
    fun notificationSwitch(switch: Int, appList: List<Int>): ByteArray {

        var result = byteArrayOf(switch.toByte())

        val result1 = fillByte(appList.subList(0, 8))
        val result2 = fillByte(appList.subList(8, 16))
        val result3 = fillByte(appList.subList(16, 24))
        val result4 = fillByte(appList.subList(24, 32))
        result = result.plus(result1).plus(result2).plus(result3).plus(result4)

        return result
    }

    /**
     * 定时心率设置0X020B
     * @param switch 开关状态（0：关闭，1：打开）
     * @param duration 测量间隔时间：0~255分
     */
    fun timeHeart(
        switch: Int,
        startHour: Int,
        startMinute: Int,
        endHout: Int,
        endMinute: Int,
        duration: Int
    ): ByteArray {
        return byteArrayOf(
            switch.toByte(),
            startHour.toByte(),
            startMinute.toByte(),
            endHout.toByte(),
            endMinute.toByte(),
            duration.toByte()
        )
    }

    /**
     * 喝水提醒设置0X020C
     * @param switch 开关状态（0：关闭，1：打开）
     * @param duration 喝水间隔时间：0~255分
     */
    fun drinkRemind(
        switch: Int,
        startHour: Int,
        startMinute: Int,
        endHout: Int,
        endMinute: Int,
        duration: Int
    ): ByteArray {
        return byteArrayOf(
            switch.toByte(),
            startHour.toByte(),
            startMinute.toByte(),
            endHout.toByte(),
            endMinute.toByte(),
            duration.toByte()
        )
    }

    /**
     * 吃药提醒设置0X020D
     * @param switch 开关状态（0：关闭，1：打开）
     */
    fun medicineRemind(
        switch: Int,
        hour: Int,
        minute: Int
    ): ByteArray {
        return byteArrayOf(
            switch.toByte(),
            hour.toByte(),
            minute.toByte(),
        )
    }

    /**
     * 生理期设置0X020E
     * @param switch 开关状态（0：关闭，1：打开）
     * @param year 开始时间（2023年，写23）
     * @param month 开始时间（月）
     * @param day 开始时间（月）
     * @param duration 持续时间（天）
     */
    fun period(
        switch: Int,
        year: Int,
        month: Int,
        day: Int,
        duration: Int
    ): ByteArray {
        return byteArrayOf(
            switch.toByte(),
            year.toByte(),
            month.toByte(),
            day.toByte(),
            duration.toByte()
        )
    }

    /**
     * 定时体温设置0X020F
     * @param switch 开关状态（0：关闭，1：打开）
     * @param duration 体温测量间隔时间：0~255分
     */
    fun bodyTemperature(
        switch: Int,
        startHour: Int,
        startMinute: Int,
        endHout: Int,
        endMinute: Int,
        duration: Int
    ): ByteArray {
        return byteArrayOf(
            switch.toByte(),
            startHour.toByte(),
            startMinute.toByte(),
            endHout.toByte(),
            endMinute.toByte(),
            duration.toByte()
        )
    }


    /**
     *  防丢设置0X0210
     *  @param switch 开关状态（0：关闭，1：打开）
     */
    fun antiLose(switch: Int): ByteArray = byteArrayOf(switch.toByte())

    /**
     *  公英制设置0X0211
     *  @param type 0：公制，1：英制
     */
    fun inchType(type: Int): ByteArray = byteArrayOf(type.toByte())

    /**
     *  天气温度单位0X0212
     *  @param type 0：摄氏度，1：华氏度
     */
    fun temperatureType(type: Int): ByteArray = byteArrayOf(type.toByte())

    /**
     * SOS联系人设置0X0213
     * @param type 类型 "新增：0X00 修改：0X01 删除：0X02"
     * @param number 号码
     * @param name 名称
     */
    fun sos(type: Int, id: Int, number: String, name: String): ByteArray {
        //电话号是20位，如果不足20位用" "代替
        var num = ""
        num = num.plus(number)
        for (i in 0 until (20 - number.length)) {
            num = num.plus(" ")
        }

        val bType = byteArrayOf(type.toByte())
        val bId = byteArrayOf(id.toByte())
        val bNum = num.toByteArray(Charsets.UTF_8)
        val bName = name.toByteArray(Charsets.UTF_8)

        Log.d(
            TAG,
            "bType : $bType  ;  bNum:  >>  ${ByteUtils.toHexString(bNum)}   ;   bName: >>  ${
                ByteUtils.toHexString(bName)
            }"
        )

        val result: ByteArray = bType.plus(bId).plus(bNum).plus(bName)
        Log.d(TAG, "sos: $result  >>  ${ByteUtils.toHexString(result)}")
        return result
    }

    /**
     *  手表控制通话 0x0215  只有设备能发送
     */

    /**
     *  找手机功能 0X0216：（手机点击响铃关闭弹窗，下发关闭响铃）
     *  @param type "00：打开响铃  01：关闭响铃"
     */
    fun findPhone(type: Int): ByteArray = byteArrayOf(type.toByte())

    /**
     *  找手表 0x0217
     */
    fun findWatch(): ByteArray = byteArrayOf()

    /**
     *  拍照控制 0X0218
     *  @param type "01:打开相机  02:退出相机"
     */
    fun photoControl(type: Int): ByteArray = byteArrayOf(type.toByte())

    /**
     * 用户信息设置 0x0219
     * @param sex 性别（0：男，1：女）
     * @param age 年龄
     * @param height 身高（cm）
     * @param weight 体重（kg）
     */
    fun userInfo(sex: Int, age: Int, height: Int, weight: Int): ByteArray {
        return byteArrayOf(0x00, sex.toByte(), age.toByte(), height.toByte(), weight.toByte())
    }

    //endregion

    /**
     * 消息推送 0X0401
     * @param timestamp 时间戳 1~4
     * @param title 消息标题 5~44
     * @param msg 消息内容 最大250字节 45~n
     */
    fun notifyMsg(id: Int, timestamp: Long, title: String, msg: String): ByteArray {
        //App ID
        val bId = byteArrayOf(id.toByte())
        //时间戳
        val timeStamp = timestampToByteArray(/*System.currentTimeMillis()*/timestamp)
        //消息标题
        val bTitle = title.toByteArray(Charsets.UTF_8).padTo(40)
        //消息内容
        var bMsg = msg.toByteArray(Charsets.UTF_8)
        if (bMsg.size > 250) {
            bMsg = bMsg.copyOf(250)
        }

        return bId.plus(timeStamp).plus(bTitle).plus(bMsg)
    }

    /**
     * 天气推送 0X0403
     *
     */
    fun currentWeather(
        geoBean: HomeZoneBean,
        weatherBean: HomeWeatherBean,
        futureWeatherBean: HomeFutureWeatherBean,
        timestamp: Long
    ): ByteArray {

        //地址 长春,朝阳
        val adm2 = geoBean.rawGeoBean?.location?.get(0)?.adm2 ?: ""
        val name = geoBean.rawGeoBean?.location?.get(0)?.name ?: ""
        val geo = "${adm2},${name}"
        val bGeo = geo.toByteArray(Charsets.UTF_8)
        val bGeoLength = byteArrayOf(bGeo.size.toByte())
        //时间戳
        val bTimeStamp = timestampToByteArray(timestamp)
        //当前温度
        val bCurrent = weatherBean.rawWeatherBean?.now?.temp?.toByte() ?: 0
        //最高温
        val tempMax = futureWeatherBean.rawWeatherBean?.daily?.get(0)?.tempMax?.toInt() ?: 0
        var bTempMax = tempMax.absoluteValue.toByte()
        bTempMax = if (tempMax < 0) bTempMax.or(0x80.toByte()) else bTempMax
        //最低温
        val tempMin = futureWeatherBean.rawWeatherBean?.daily?.get(0)?.tempMin?.toInt() ?: 0
        var bTempMin = tempMin.absoluteValue.toByte()
        bTempMin = if (tempMin < 0) bTempMin.or(0x80.toByte()) else bTempMin

        Log.d(TAG, "天气推送: $bCurrent  >> $tempMax  >> $tempMin")
        Log.d(TAG, "天气推送: $bCurrent  >> $bTempMax  >> $bTempMin")
        //天气类型
        val bType = changeWeatherType(weatherBean.rawWeatherBean?.now?.icon?.toInt() ?: -1).toByte()
        //湿度
        val bHumidity = weatherBean.rawWeatherBean?.now?.humidity?.toInt()?.toByte() ?: 0
        //降雨量
        val precip = weatherBean.rawWeatherBean?.now?.precip ?: "0"
        val split = precip.split(".")
        val iPrecip = split[0].toInt()
        val bPrecip = iPrecip.toByte()
        //风速
        val bWindSpeed = weatherBean.rawWeatherBean?.now?.windSpeed?.toInt()?.toByte() ?: 0
        //紫外线等级
        val bUv = futureWeatherBean.rawWeatherBean?.daily?.get(0)?.uvIndex?.toInt()?.toByte() ?: 0

        return bGeoLength.plus(bGeo).plus(bTimeStamp).plus(bCurrent).plus(bTempMax).plus(bTempMin)
            .plus(bType).plus(bHumidity).plus(bPrecip).plus(bWindSpeed).plus(bUv)
    }


    /**
     * 未来天气推送 0X0404
     *
     */
    fun futureWeather(
        geoBean: HomeZoneBean,
        futureWeatherBean: HomeFutureWeatherBean
    ): ByteArray {
        var result: ByteArray = byteArrayOf()

        //地址 长春,朝阳
        val adm2 = geoBean.rawGeoBean?.location?.get(0)?.adm2 ?: ""
        val name = geoBean.rawGeoBean?.location?.get(0)?.name ?: ""
        val geo = "${adm2},${name}"
        val bGeo = geo.toByteArray(Charsets.UTF_8)
        val bGeoLength = byteArrayOf(bGeo.size.toByte())

        result = result.plus(bGeoLength).plus(bGeo)

        //未来天气for in
        val dataSize = futureWeatherBean.rawWeatherBean?.daily?.size ?: 0
        for (i in 0 until dataSize) {
            //时间戳
            val rawTimeStamp =
                futureWeatherBean.rawWeatherBean?.daily?.get(i)?.fxDate ?: "1970-01-01"
            val dateToTimeStamp = dateToTimeStamp(rawTimeStamp)
            val bTimeStamp = dateTimestampToByteArray(dateToTimeStamp)

            //最高温
            val tempMax = futureWeatherBean.rawWeatherBean?.daily?.get(i)?.tempMax?.toInt() ?: 0
            var bTempMax = tempMax.absoluteValue.toByte()
            bTempMax = if (tempMax < 0) bTempMax.or(0x80.toByte()) else bTempMax
            //最低温
            val tempMin = futureWeatherBean.rawWeatherBean?.daily?.get(i)?.tempMin?.toInt() ?: 0
            var bTempMin = tempMin.absoluteValue.toByte()
            bTempMin = if (tempMin < 0) bTempMin.or(0x80.toByte()) else bTempMin
            //天气类型
            val bType = changeWeatherType(
                futureWeatherBean.rawWeatherBean?.daily?.get(i)?.iconDay?.toInt() ?: -1
            ).toByte()
            //湿度
            val bHumidity =
                futureWeatherBean.rawWeatherBean?.daily?.get(i)?.humidity?.toInt()?.toByte() ?: 0
            //降雨量
            val precip = futureWeatherBean.rawWeatherBean?.daily?.get(i)?.precip ?: "0"
            val split = precip.split(".")
            val iPrecip = split[0].toInt()
            val bPrecip = iPrecip.toByte()
            //风速
            val bWindSpeed =
                futureWeatherBean.rawWeatherBean?.daily?.get(i)?.windSpeedDay?.toInt()?.toByte()
                    ?: 0
            //紫外线等级
            val bUv =
                futureWeatherBean.rawWeatherBean?.daily?.get(0)?.uvIndex?.toInt()?.toByte() ?: 0
            result =
                result.plus(bTimeStamp).plus(bTempMax).plus(bTempMin).plus(bType).plus(bHumidity)
                    .plus(bPrecip).plus(bWindSpeed).plus(bUv)
        }
        //for out
        return result
    }

    /**
     * 来电推送 0X0406
     * @param type 电话类型
     * @param timestamp 时间戳 1~4
     * @param name 来电姓名
     * @param phone 来电号码
     */
    fun notifyMsgPhone(type: Int, timestamp: Long, name: String, phone: String): ByteArray {
        //电话类型
        val bId = byteArrayOf(type.toByte())
        //时间戳
        val timeStamp = timestampToByteArray(/*System.currentTimeMillis()*/timestamp)
        //来电姓名
        val bName = name.toByteArray(Charsets.UTF_8)
        //来电姓名长度
        val bNameLength = bName.size.toByte()
        //电话号码
        val bPhone = phone.toByteArray(Charsets.UTF_8)
        //电话号码长度
        val bPhoneLength = bPhone.size.toByte()

        return bId.plus(timeStamp).plus(bNameLength).plus(bName).plus(bPhoneLength).plus(bPhone)
    }

    /**
     * 时间更新 0x405
     */
    fun updateTime(timestamp: Long): ByteArray {
        //结果
        val result = ByteArray(6)
        //时间戳
        val timeStamp = timestampToByteArray(timestamp)
        for (i in 0 until 4) {
            result[i] = timeStamp[i]
        }
        //星期转换
        val dayOfWeek = when (val week = Calendar.getInstance().get(Calendar.DAY_OF_WEEK)) {
            Calendar.SUNDAY -> 7
            else -> week - 1
        }
        //时区
        val rawOffset = TimeZone.getDefault().rawOffset
        val offset = rawOffset / (15 * 60 * 1000)
        //时区转换
        val zoneResult = if (offset > 0) {
            offset.absoluteValue.toByte()
        } else {
            offset.absoluteValue.toByte() or 0x80.toByte()
        }

        result[4] = dayOfWeek.toByte()
        result[5] = zoneResult

        CommonViewModel.INSTANCE.timeZoneRawOffset = rawOffset

        Log.d(TAG, "更新时间: ${ByteUtils.toHexString(result)}")

        return result
    }


    //日期转成时间戳
    @SuppressLint("SimpleDateFormat")
    private fun dateToTimeStamp(date: String): Long {
        val dateFormat = SimpleDateFormat("yyyy-MM-dd")
        return try {
            val d = dateFormat.parse(date)
            val res = d.time.div(1000)
            res
        } catch (e: ParseException) {
            Log.d(TAG, "dateToTimeStamp exception: ${e.message}")
            0L
        }
    }

    //时间戳转换成ByteArray
    private fun timestampToByteArray(timestamp: Long): ByteArray {
        val timestampInSeconds = timestamp / 1000 // 将时间戳从毫秒转换为秒
        val byteBuffer = ByteBuffer.allocate(4)
        byteBuffer.order(ByteOrder.BIG_ENDIAN) // 使用大端字节序，根据需要调整
        // 将32位整数放入ByteBuffer
        byteBuffer.putInt(timestampInSeconds.toInt())
        return byteBuffer.array()
    }

    //时间戳转换成ByteArray
    private fun dateTimestampToByteArray(timestamp: Long): ByteArray {
        val byteBuffer = ByteBuffer.allocate(4)
        byteBuffer.order(ByteOrder.BIG_ENDIAN) // 使用大端字节序，根据需要调整
        // 将32位整数放入ByteBuffer
        byteBuffer.putInt(timestamp.toInt())
        return byteBuffer.array()
    }
//
//    //时间戳转换成ByteArray
//    fun timestampToByteArray(timestamp: Long): ByteArray {
//        val timestampInSeconds = timestamp / 1000 // 将时间戳从毫秒转换为秒
//        val byteArray = ByteArray(4)
//
//        // 将32位整数拆分成4个字节
//        byteArray[0] = (timestampInSeconds ushr 24).toByte()
//        byteArray[1] = (timestampInSeconds ushr 16).toByte()
//        byteArray[2] = (timestampInSeconds ushr 8).toByte()
//        byteArray[3] = timestampInSeconds.toByte()
//
//        return byteArray
//    }

    //按位填充Byte
    private fun fillByte(data: List<Int>): Byte {
        var temp = 0.toByte()
        for ((i, d) in data.withIndex()) {
            if (d != 0)
                temp = (temp + 2.0.pow(i.toDouble()).toInt().toByte()).toByte()
        }
        Log.d(TAG, "fillByte: $temp")
        return temp
    }

    private fun changeWeatherType(type: Int): Int {
        return when (type) {
            in 100 until 110 -> type - 100
            in 150 until 160 -> type - 150
            in 300 until 320 -> type - 295
            in 350 until 352 -> type - 345
            399 -> 24
            in 400..410 -> type - 375
            in 456 until 458 -> type - 425
            499 -> 36
            in 500..504 -> type - 463
            in 507..515 -> type - 465
            900 -> 51
            901 -> 52
            else -> 255
        }
    }
}